﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using Pavilion.GameTools;

namespace Pavilion.Locks
{
    public enum CharacterToCharacterLocation { FaceToFace, BackToBack, Behind, Front, Center, CenterOppisite }

    class CharacterToCharacterLocationLock : ILock
    {
        public string GameItemName { get; set; }
        public GameItem FocusGameItem { get; set; }
        public CharacterToCharacterLocation Location { get; set; }
        public float CenterRadius { get; set; }

        public ILock Clone()
        {
            return new CharacterToCharacterLocationLock()
            {
                FocusGameItem = this.FocusGameItem,
                GameItemName = this.GameItemName,
                Location = this.Location,
                CenterRadius = this.CenterRadius
            };
        }

        public void Deserialize(XElement lockElement, string resourceName)
        {
            string gameItemName = lockElement.Attribute("FocusGameItem").Value;

            if (!string.IsNullOrEmpty(gameItemName))
                FocusGameItem = GameItemManager.Instance[gameItemName];

            Location = GameEngine.EnumParse<CharacterToCharacterLocation>(lockElement.Attribute("Location").Value);
            CenterRadius = GameEngine.ParseObject<float>(lockElement.Attribute("CenterRadius").Value);
        }

        public XElement Serialize()
        {
            XElement lockElement = new XElement("Lock");

            lockElement.Add(new XAttribute("FocusGameItem", (FocusGameItem == null) ? "" : FocusGameItem.Name));
            lockElement.Add(new XAttribute("Location", Location));
            lockElement.Add(new XAttribute("CenterRadius", CenterRadius));

            return lockElement;
        }

        public LockMonitorBase CreateLockMonitor(GameItem gameItem)
        {
            PolygonPhysicalData targetPolygonData = gameItem.ObtainTool<PhysicalTypeTool>().PolygonData;
            PolygonPhysicalData focusPolygonData = null;

            if (FocusGameItem != null)
                focusPolygonData = FocusGameItem.ObtainTool<PhysicalTypeTool>().PolygonData;

            return new CharacterToCharacterLocationLockMonitor(this, focusPolygonData, targetPolygonData);
        }

        public class CharacterToCharacterLocationLockMonitor : LockMonitorBase
        {
            public override ILock Lock { get { return lockItem; } }

            private PolygonPhysicalData focusPolygonData, targetPolygonData;
            private CharacterToCharacterLocationLock lockItem;

            public CharacterToCharacterLocationLockMonitor(CharacterToCharacterLocationLock lockItem, PolygonPhysicalData focusPolygonData, PolygonPhysicalData targetPolygonData)
            {
                this.lockItem = lockItem;
                this.focusPolygonData = focusPolygonData;
                this.targetPolygonData = targetPolygonData;
            }

            public override void Dispose()
            {
                if (focusPolygonData != null)
                {
                    targetPolygonData.PositionChanged -= PolygonData_PositionChanged;
                    focusPolygonData.PositionChanged -= PolygonData_PositionChanged;
                    focusPolygonData.IsFlippedHorizontallyChanged -= PolygonData_IsFlippedHorizontallyChanged;
                    targetPolygonData.IsFlippedHorizontallyChanged -= PolygonData_IsFlippedHorizontallyChanged;
                }

                targetPolygonData = null;
                focusPolygonData = null;
            }

            public override void Load(GameItem gameItem)
            {
                if (focusPolygonData != null)
                {
                    focusPolygonData.PositionChanged += PolygonData_PositionChanged;
                    targetPolygonData.PositionChanged += PolygonData_PositionChanged;
                    focusPolygonData.IsFlippedHorizontallyChanged += PolygonData_IsFlippedHorizontallyChanged;
                    targetPolygonData.IsFlippedHorizontallyChanged += PolygonData_IsFlippedHorizontallyChanged;
                }

                UpdateLock();
            }

            public override void UpdateLock()
            {
                if (focusPolygonData == null)
                    return;

                bool isOpenTemp = false;
                Direction location = DetermineTargetLocation();

                if (location == Direction.Right)
                {
                    if (targetPolygonData.IsFlippedHorizontally)
                    {
                        if (!focusPolygonData.IsFlippedHorizontally)
                            isOpenTemp = lockItem.Location == CharacterToCharacterLocation.FaceToFace;
                        else
                            isOpenTemp = lockItem.Location == CharacterToCharacterLocation.Behind;
                    }
                    else
                    {
                        if (focusPolygonData.IsFlippedHorizontally)
                            isOpenTemp = lockItem.Location == CharacterToCharacterLocation.BackToBack;
                        else
                            isOpenTemp = lockItem.Location == CharacterToCharacterLocation.Front;
                    }
                }
                else if (location == Direction.Left)
                {
                    if (targetPolygonData.IsFlippedHorizontally)
                    {
                        if (!focusPolygonData.IsFlippedHorizontally)
                            isOpenTemp = lockItem.Location == CharacterToCharacterLocation.BackToBack;
                        else
                            isOpenTemp = lockItem.Location == CharacterToCharacterLocation.Front;
                    }
                    else
                    {
                        if (focusPolygonData.IsFlippedHorizontally)
                            isOpenTemp = lockItem.Location == CharacterToCharacterLocation.FaceToFace;
                        else
                            isOpenTemp = lockItem.Location == CharacterToCharacterLocation.Behind;
                    }
                }
                else
                {
                    if (targetPolygonData.IsFlippedHorizontally == focusPolygonData.IsFlippedHorizontally)
                        isOpenTemp = lockItem.Location == CharacterToCharacterLocation.Center;
                    else
                        isOpenTemp = lockItem.Location == CharacterToCharacterLocation.CenterOppisite;
                }

                IsOpen = isOpenTemp;
            }

            private void PolygonData_PositionChanged(PhysicalData physicalData)
            {
                UpdateLock();
            }

            private void PolygonData_IsFlippedHorizontallyChanged(PhysicalData physicalData)
            {
                UpdateLock();
            }

            private Direction DetermineTargetLocation()
            {
                if (focusPolygonData.Position.X - lockItem.CenterRadius > targetPolygonData.Position.X)
                    return Direction.Left;
                else if (focusPolygonData.Position.X + lockItem.CenterRadius < targetPolygonData.Position.X)
                    return Direction.Right;
                else
                    return Direction.Center;
            }
        }
    }
}
